﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace B121B {
    /// <summary>
    /// Van class
    /// </summary>
    public class Van : Vehicle, IHasLoadCapacity {
        /// <summary>
        /// Vehicle constructor
        /// </summary>
        /// <param name="brand">Brand</param>
        /// <param name="model">Model</param>
        /// <param name="km">Distance driven</param>
        /// <param name="year">Production year</param>
        /// <param name="price">Price</param>
        /// <param name="motorSize">Size of motor</param>
        /// <param name="km_l">Travel distance on 1 liter of fuel</param>
        /// <param name="fueltype">Fueltype</param>
        /// <param name="loadCapacity">Load capacity</param>
        /// <param name="dimensions">Dimensions of the trunk</param>
        public Van(string brand, string model, int km, DateTime year, int price, double motorSize, double km_l, Fuel fueltype, int loadCapacity, TrunkDimensions dimensions)
            : base(brand, model, km, year, price, motorSize, km_l, fueltype) {
            LoadCapacity = loadCapacity;
            TrunkSpace = dimensions;
            VehicleType = VehicleTypes.Van;
        }

        #region Properties
        /// <summary>
        /// Load capacity
        /// </summary>
        public int LoadCapacity {
            get { return _LoadCapacity; }
            set {
                if (value < 0) { // Checks for valid capacity
                    throw new ArgumentOutOfRangeException("The load capacity cannot be negative");
                } else {
                    _LoadCapacity = value;
                }
            }
        }
        private int _LoadCapacity;

        /// <summary>
        /// Dimensions of the trunk
        /// </summary>
        public TrunkDimensions TrunkSpace {
            get { return _TrunkSpace; }
            set {
                if (value == null) { // Check for null value
                    throw new ArgumentNullException();
                } else {
                    _TrunkSpace = value;
                }
            }
        }
        private TrunkDimensions _TrunkSpace;

        /// <summary>
        /// Max speed
        /// </summary>
        public override int MaxSpeed { get { return 200; } } // Max speed is locked at 200, as per assignment

        /// <summary>
        /// Motor size
        /// </summary>
        public override double MotorSize {
            get { return _MotorSize; }
            set {
                if (!IsMotorSizeOkay(2.0, 4.2, value)) { // Check for valid size
                    throw new ArgumentOutOfRangeException();
                } else {
                    _MotorSize = value;
                }
            }
        }
        private double _MotorSize;
        #endregion

        /// <summary>
        /// Shows van information, formatted for console output
        /// </summary>
        /// <returns>Van information</returns>
        public override string ToString() {
            return base.ToString() + Environment.NewLine +
                "  Load capacity: " + LoadCapacity + Environment.NewLine +
                "  Trunk dimensions: " + TrunkSpace + " MxMxM";
        }

        #region Override Equals
        public override bool Equals(object obj) {
            if (obj == null) { return false; } // Check for null

            // We don't check for reference equality

            if (this.GetType() != obj.GetType()) { return false; } // Same type?

            return Equals((Van)obj); // More specific check
        }
        public bool Equals(Van obj) {
            if (obj == null) { return false; }

            return // Check all values
                base.Equals(obj) &&
                this.LoadCapacity == obj.LoadCapacity &&
                this.TrunkSpace == obj.TrunkSpace;
        }
        public override int GetHashCode() {
            return base.GetHashCode(); // We do not check has code, as we check on values only
        }

        public static bool operator ==(Van obj1, Van obj2) {
            if (ReferenceEquals(obj1, null)) {
                return ReferenceEquals(obj2, null); // Both null, equal, otherwise not
            }
            return obj1.Equals(obj2);
        }
        public static bool operator !=(Van obj1, Van obj2) {
            return !(obj1 == obj2);
        }
        #endregion

        public class TrunkDimensions {
            /// <summary>
            /// Dimensions of the trunk
            /// </summary>
            /// <param name="height">Height</param>
            /// <param name="width">Width</param>
            /// <param name="length">Depth</param>
            public TrunkDimensions(double height, double width, double length) {
                Height = height;
                Width = width;
                Length = length;
            }

            /// <summary>
            /// Height of the trunk
            /// </summary>
            public double Height {
                get { return _Height; }
                set {
                    if (value < 0) { // Check for valid dimension
                        throw new ArgumentOutOfRangeException("The height cannot be less than 0");
                    } else {
                        _Height = value;
                    }
                }
            }
            private double _Height;

            /// <summary>
            /// Width of the trunk
            /// </summary>
            public double Width {
                get { return _Width; }
                set {
                    if (value < 0) { // Check for valid dimension
                        throw new ArgumentOutOfRangeException("The width cannot be less than 0");
                    } else {
                        _Width = value;
                    }
                }
            }
            private double _Width;

            /// <summary>
            /// Length of the trunk
            /// </summary>
            public double Length {
                get { return _Length; }
                set {
                    if (value < 0) { // Check for valid dimension
                        throw new ArgumentOutOfRangeException("The length cannot be less than 0");
                    } else {
                        _Length = value;
                    }
                }
            }
            private double _Length;

            /// <summary>
            /// Shows the dimensions of the trunk formatted for console output
            /// </summary>
            /// <returns>Trunk dimensions</returns>
            public override string ToString() {
                return Height.ToString() + "x" + Width.ToString() + "x" + Length.ToString();
            }

            #region Override Equals
            public override bool Equals(object obj) {
                if (obj == null) { return false; } // Check for null

                // We don't check for reference equality

                if (this.GetType() != obj.GetType()) { return false; } // Same type?

                return Equals((Van)obj); // More specific check
            }
            public bool Equals(TrunkDimensions obj) {
                if (obj == null) { return false; }

                return // Check all values
                    base.Equals(obj) &&
                    this.Height == obj.Height &&
                    this.Width == obj.Width &&
                    this.Length == obj.Length;
            }
            public override int GetHashCode() {
                return base.GetHashCode(); // We do not check has code, as we check on values only
            }

            public static bool operator ==(TrunkDimensions obj1, TrunkDimensions obj2) {
                if (ReferenceEquals(obj1, null)) {
                    return ReferenceEquals(obj2, null); // Both null, equal, otherwise not
                }
                return obj1.Equals(obj2);
            }
            public static bool operator !=(TrunkDimensions obj1, TrunkDimensions obj2) {
                return !(obj1 == obj2);
            }
            #endregion
        }
    }
}
